package com.apes.scm.voucher.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.BaseModel;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.*;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.masterdata.car.repository.CarConfigurationRepository;
import com.apes.scm.masterdata.car.repository.CarModelServiceLevelRepository;
import com.apes.scm.masterdata.party.model.ChangeCompany;
import com.apes.scm.masterdata.product.repository.ServeCategoryRepository;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherExtension;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherExtensionRepository;
import com.apes.scm.voucher.repository.VoucherItemRepository;
import com.apes.scm.voucher.repository.VoucherRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
 * @BelongsProject: apes-server
 * @BelongsPackage: com.apes.scm.voucher.service
 * @ClassName: VoucherExtensionService
 * @Author: pyb
 * @Description: 业务凭证扩展服务
 * @CreateTime: 2021-03-12 14:29
 * @Version: 1.0
 */
@Service("voucherExtensionService")
public class VoucherExtensionService extends DomainService {
    @Autowired
    private VoucherExtensionRepository voucherExtensionRepository;
    @Autowired
    private VoucherRepository voucherRepository;
    @Autowired
    private ServeCategoryRepository serveCategoryRepository;
    @Autowired
    private CarConfigurationRepository carConfigurationRepository;
    @Autowired
    private CarModelServiceLevelRepository carModelServiceLevelRepository;


    /**
     * 生成业务凭证扩展表
     *
     * @param request
     */
    private void generateVoucherExtension(SimpleRequest request) {
        Voucher voucher = request.getO(Voucher.class);
        buildVoucherExtension(voucher);
    }

    /**
     * 批量更新凭证扩展
     */
    public void bulkUpdateVoucherExtension(SimpleRequest request) {
        int page = request.get("page");
        int size = request.get("size");
        Sort sort = new Sort(Sort.Direction.ASC, "createDate");
        while (true) {
            Pageable pageable = PageRequest.of(page, size, sort);
            int execute = 0;
            try {
                execute = execute(() -> {
                    Page<Voucher> vouchers = voucherRepository.findAll(pageable);
                    vouchers.getContent().forEach(this::buildVoucherExtension);
                    return vouchers.getContent().size();
                });
            } catch (Exception e) {
                //即使异常也不处理，宁愿不汇扩展表也不要影响业务
            }
            page = page + 1;
            if (execute < size) {
                break;
            }
        }

    }

    /**
     * 构建业务凭证扩展表
     *
     * @param voucher
     */
    private void buildVoucherExtension(Voucher voucher) {
        voucher.getVoucherItems().forEach(voucherItem -> {
            VoucherExtension voucherExtension = Optional.ofNullable(voucherExtensionRepository.findOne(voucherItem.getId())).orElse(new VoucherExtension());

            voucherExtension.setId(voucherItem.getId());
            voucherExtension.setVoucherItemId(voucherItem.getId());
            voucherExtension.setDeptName(voucher.getDept().getName());

            voucherExtension.setUomName(voucherItem.getUom().getName());
            voucherExtension.setTaxName(voucherItem.getTax().getName());

            voucherExtension.setCompanyName(voucher.getCompany().getName());
            voucherExtension.setPartnerName(voucher.getPartner().getName());

            voucherExtension.setProductName(voucherItem.getProduct().getName());
            voucherExtension.setProductState(voucherItem.getProduct().getState());

            voucherExtension.setBrandName(voucherItem.getProduct().getBrand().getName());
            voucherExtension.setOriginBusinessTypeName(voucher.getOriginBusinessTypeName());
            voucherExtension.setSourceBusinessTypeName(voucher.getSourceBusinessTypeName());

            voucherExtension.setProductClassify(voucherItem.getProduct().getClassify().getName());
            voucherExtension.setProductClassifyId(voucherItem.getProduct().getClassify().getId());
            voucherExtension.setProductGroupName(voucherItem.getProduct().getProductGroup().getName());

            Optional.ofNullable(voucher.getClerk()).ifPresent(clerk -> voucherExtension.setClerk(clerk.getName()));
            Optional.ofNullable(voucher.getContract()).ifPresent(contract -> voucherExtension.setContractName(contract.getName()));
            Optional.ofNullable(voucherItem.getSupplier()).ifPresent(supplier -> voucherExtension.setSupplierName(supplier.getName()));
            Optional.ofNullable(voucherItem.getProduct().getCategory()).ifPresent(
                    category -> {
                        voucherExtension.setCategoryId(category.getId());
                        voucherExtension.setCategoryName(category.getName());
                    });

            serveCategoryRepository.findAll(JpaDsl.toCriteriaByEq("classify.id", voucherItem.getProduct().getClassify().getId())).stream().findFirst().ifPresent(
                    serveCategory -> {
                        voucherExtension.setServeTypeId(serveCategory.getServeType().getId());
                        voucherExtension.setServeTypeName(serveCategory.getServeType().getName());
                    });

            //会员扩展信息不为空
            Optional.ofNullable(voucher.getCustomerExpand()).ifPresent(customerExpand -> setCustomerExpand(voucherExtension, customerExpand));
            //会员扩展信息为空
            isNullCustomerExpand(voucher, voucherItem, voucherExtension);
            //写入单据记账日期(特定单据)
            voucherExtension.setBookDate(obtainBookDate(voucher));
            //来源单据公司（异业）
            voucherExtension.setOriginCompany(voucher.getOriginCompany());
            //保存
            voucherExtensionRepository.saveAndFlush(voucherExtension);
        });
    }

    /**
     * 处理会员扩展信息为空的情况
     *
     * @param voucher
     * @param voucherItem
     * @param voucherExtension
     */
    private void isNullCustomerExpand(Voucher voucher, VoucherItem voucherItem, VoucherExtension voucherExtension) {
        if (Tools.isNull(voucher.getCustomerExpand())) {
            //来源为采购
            if (Objects.equals("PurchaseOrder", voucher.getOriginBusinessType())) {
                //根据采购订单的可溯源性反找要货单
                traceabilityPurchaseOrder(voucherExtension, voucher.getOrigin());
            }
            //其他来源
            if (LogicalUtil.in(voucher.getOriginBusinessType(), "RetailOrder", "RetailReturn", "ServicePlan", "SaleOrder", "SaleReturn")) {
                //赋值
                setCustomerExpand(voucherExtension, voucher.getOriginBusinessType(), voucher.getOrigin());
            } else {
                //来源为返厂类的（非销售非服务）
                if (Objects.equals("SUPPLIER_PURCHASE", voucher.getVoucherType()) && voucher.isReturned()) {
                    Optional.of(voucherItem.getInventoryBatch().getId()).ifPresent(batchId -> {
                        //获取批次
                        InventoryBatch inventoryBatch = SpringManager.getBean(InventoryBatchRepository.class).findOne(batchId);
                        //根据采购批次获取采购凭证
                        Optional.ofNullable(SpringManager.getBean(VoucherItemRepository.class).findOne(inventoryBatch.getBatchNumber())).ifPresent(purItem -> {
                            if (Objects.equals("PurchaseOrder", purItem.getVoucher().getOriginBusinessType())) {
                                //根据采购订单的可溯源性反找要货单
                                traceabilityPurchaseOrder(voucherExtension, purItem.getVoucher().getOrigin());
                            }
                            if (LogicalUtil.in(purItem.getVoucher().getOriginBusinessType(), "RetailOrder", "RetailReturn", "ServicePlan", "SaleOrder", "SaleReturn")) {
                                //赋值
                                setCustomerExpand(voucherExtension, purItem.getVoucher().getOriginBusinessType(), purItem.getVoucher().getOrigin());
                            }
                        });

                    });


                }
            }
        }
    }

    /**
     * 根据来源单据和类型赋值会员扩展信息
     *
     * @param voucherExtension
     * @param originBusinessType
     * @param origin
     */
    private void setCustomerExpand(VoucherExtension voucherExtension, String originBusinessType, String origin) {
        //获取实体的领域类
        String domainTypeName = JpaUtil.getAllDomainType().stream()
                .filter(s -> ReflectUtil.getClass(s).getSimpleName().equalsIgnoreCase(originBusinessType))
                .findFirst().orElse(null);
        CustomRepository repository = JpaUtil.getRepository(domainTypeName);
        Serializable id = JpaUtil.getId(domainTypeName, origin);
        Object model = repository != null ? repository.findOne(id) : null;
        if (model == null) return;

        Object fnCustomerExpand = ReflectUtil.getFieldValue(model, "fnCustomerExpand");
        if (Objects.isNull(fnCustomerExpand)) {
            Object customerExpand = ReflectUtil.getFieldValue(model, "customerExpand");
            if (Objects.nonNull(customerExpand)) {
                if (customerExpand instanceof BaseModel) {
                    setCustomerExpand(voucherExtension, String.valueOf(((BaseModel) customerExpand).getInnerBusinessKey()));
                } else {
                    setCustomerExpand(voucherExtension, String.valueOf(customerExpand));
                }
            }
        } else {
            if (fnCustomerExpand instanceof BaseModel) {
                setCustomerExpand(voucherExtension, ((BaseModel) fnCustomerExpand).getInnerBusinessKey());
            } else {
                setCustomerExpand(voucherExtension, String.valueOf(fnCustomerExpand));
            }
        }
    }

    /**
     * 填充会员扩展信息
     *
     * @param voucherExtension
     * @param customerExpand
     */
    private void setCustomerExpand(VoucherExtension voucherExtension, String customerExpand) {
        if (Objects.isNull(customerExpand)) return;
        BaseModel model = invoke("fn.customerExpand.findOne", MapUtil.mapper("id", customerExpand));
        Optional.ofNullable(model).ifPresent(expand -> {
            voucherExtension.setVin(ReflectUtil.getFieldValue(expand, "vin"));
            voucherExtension.setMobile(ReflectUtil.getFieldValue(expand, "mobile"));
            voucherExtension.setRealname(ReflectUtil.getFieldValue(expand, "realname"));
            voucherExtension.setCarLicense(ReflectUtil.getFieldValue(expand, "carLicense"));
            voucherExtension.setCarModelLabel(ReflectUtil.getFieldValue(expand, "carModelLabel"));
            voucherExtension.setJekunModelCode(ReflectUtil.getFieldValue(expand, "jekunModelCode"));
            //车型服务等级
            Optional.ofNullable(voucherExtension.getJekunModelCode()).flatMap(code ->
                            Optional.ofNullable(carConfigurationRepository.findOne(voucherExtension.getJekunModelCode()))
                            .flatMap(carConfiguration -> carModelServiceLevelRepository.findAll(
                                    JpaDsl.toCriteriaByEq("carModel.id", carConfiguration.getCarModel().getId())).stream().findFirst()))
                    .ifPresent(carModelServiceLevel -> voucherExtension.setCarServiceLevel(carModelServiceLevel.getCarServiceLevel().getName()));
        });
    }


    /**
     * 追溯采购订单来源
     *
     * @param voucherExtension
     * @param origin
     */
    private void traceabilityPurchaseOrder(VoucherExtension voucherExtension, String origin) {
        PurchaseOrder purchaseOrder = SpringManager.getBean(PurchaseOrderRepository.class).findOne(origin);
        if (purchaseOrder == null) return;
        if (Objects.equals("ProductRequire", purchaseOrder.getOriginBusinessType())) {
            //获取实体的领域类
            String domainTypeName = JpaUtil.getAllDomainType().stream()
                    .filter(s -> "ProductRequire".equalsIgnoreCase(ReflectUtil.getClass(s).getSimpleName()))
                    .findFirst().orElse(null);
            CustomRepository repository = JpaUtil.getRepository(domainTypeName);
            Serializable id = JpaUtil.getId(domainTypeName, purchaseOrder.getOrigin());
            Object model = repository != null ? repository.findOne(id) : null;
            if (Objects.isNull(model)) return;

            Object customerExpand = ReflectUtil.getFieldValue(model, "customerExpand");
            if (Objects.nonNull(customerExpand)) {
                setCustomerExpand(voucherExtension, ((BaseModel) customerExpand).getInnerBusinessKey());
            }
        }
    }


    /**
     * 获取单据的记账日期(特定单据)
     *
     * @param voucher
     * @return
     */
    private Date obtainBookDate(Voucher voucher) {
        if (LogicalUtil.in(voucher.getSourceBusinessType(), "RetailOrder", "RetailReturn", "SaleOrder", "SaleReturn")) {
            boolean flag = Objects.equals("RetailOrder", voucher.getSourceBusinessType());
            Date bookDate = getBookDate(voucher, flag ? "dateApprove" : "dateDone");
            if (bookDate != null) return bookDate;
        }else if (LogicalUtil.in(voucher.getSourceBusinessType(), "Voucher") && LogicalUtil.in(voucher.getOriginBusinessType(), "RetailOrder")){
            //异业部分
            Date bookDate = getBookDate(voucher, "dateApprove");
            if (bookDate != null) return bookDate;
        }
        return voucher.getCreateDate();
    }

    private Date getBookDate(Voucher voucher, String field) {
        //获取实体的领域类
        String domainTypeName = JpaUtil.getAllDomainType().stream()
                .filter(s -> voucher.getSourceBusinessType().equalsIgnoreCase(ReflectUtil.getClass(s).getSimpleName()))
                .findFirst().orElse(null);
        CustomRepository repository = JpaUtil.getRepository(domainTypeName);
        Serializable id = JpaUtil.getId(domainTypeName, voucher.getSource());
        Object model = repository != null ? repository.findOne(id) : null;
        if (Objects.nonNull(model)) {
            Object bookDate = ReflectUtil.getFieldValue(model, field);
            if (Objects.nonNull(bookDate)) {
                return (Date) bookDate;
            }
        }
        return null;
    }

    @Autowired
    private TransactionTemplate transactionTemplate;

    public int execute(Callback callback) {
        return transactionTemplate.execute(status -> {
            try {
                return callback.execute();
            } catch (Exception e) {
                status.isRollbackOnly();
                throw e;
            }
        });
    }

    @FunctionalInterface
    public interface Callback {
        @Nullable
        int execute();
    }
}
